home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / shells / bashsrc.zoo / test.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-05  |  16.8 KB  |  758 lines

  1. /*
  2.  * GNU test program (ksb and mjb)
  3.  *
  4.  * Modified to run with the GNU shell Apr 25, 1988 by bfox.
  5.  *
  6.  *???    -G    file is owned by same gid; the effective gid is checked
  7.  * Chet Ramey, CWRU 3/23/89
  8.  *
  9.  * Fixed a BSD dependency (_doprnt()) in the port to AIX 2.2
  10.  * Chet Ramey, CWRU 5/3/89
  11.  */
  12.  
  13. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  14.  
  15. This file is part of GNU Bash, the Bourne Again SHell.
  16.  
  17. Bash is free software; you can redistribute it and/or modify it under
  18. the terms of the GNU General Public License as published by the Free
  19. Software Foundation; either version 1, or (at your option) any later
  20. version.
  21.  
  22. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  23. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  24. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  25. for more details.
  26.  
  27. You should have received a copy of the GNU General Public License along
  28. with Bash; see the file COPYING.  If not, write to the Free Software
  29. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  30.  
  31. #include <stdio.h>
  32. #include <varargs.h>
  33.  
  34. #ifndef SONY
  35. #include <fcntl.h>
  36. #endif
  37.  
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <sys/file.h>
  41.  
  42. #ifndef R_OK
  43. #define R_OK 4
  44. #define W_OK 2
  45. #define X_OK 1
  46. #define F_OK 0
  47. #endif
  48.  
  49. #ifndef lint
  50. static char *rcsid = "$Id: gtest.c,v 1.10 88/07/02 13:34:45 afb Exp Locker: afb $";
  51. #endif
  52.  
  53. /* The following few defines control the truth and false output of each stage.
  54.    TRUE and FALSE are what we use to compute the final output value.
  55.    SHELL_BOOLEAN is the form which returns truth or falseness in shell terms.
  56.    TRUTH_OR is how to do logical or with TRUE and FALSE.
  57.    TRUTH_AND is how to do logical and with TRUE and FALSE..
  58.    Default is TRUE = 1, FALSE = 0, TRUTH_OR = a | b, TRUTH_AND = a & b,
  59.     SHELL_BOOLEAN = (!value). */
  60. #define TRUE 1
  61. #define FALSE 0
  62. #define SHELL_BOOLEAN(value) (!(value))
  63. #define TRUTH_OR(a, b) ((a) | (b))
  64. #define TRUTH_AND(a, b) ((a) & (b))
  65.  
  66.  
  67. /* Define STANDALONE to get the /bin/test version.  Otherwise, we are
  68.    making this for the shell. */
  69. /* #define STANDALONE */
  70.  
  71. #ifdef STANDALONE
  72. #define test_exit(val) exit (val)
  73. #else
  74. #include <setjmp.h>
  75. jmp_buf test_exit_buf;
  76. int test_error_return = 0;
  77. #define test_exit(val) test_error_return = val, longjmp (test_exit_buf, 1)
  78. #endif /* STANDALONE */
  79.  
  80. #ifdef SYSV
  81. int sys_v = 1;
  82. #else
  83. int sys_v = 0;
  84. #endif
  85.  
  86. static int pos;            /* position in list            */
  87. static int argc;        /* number of args from command line    */
  88. static char **argv;        /* the argument list            */
  89.  
  90. static void
  91. test_syntax_error (format, arg)
  92.      char *format, *arg;
  93. {
  94.   (void) fprintf (stderr, "%s: ", argv[0]);
  95.   (void) fprintf (stderr, format, arg);
  96.   test_exit (SHELL_BOOLEAN (FALSE));
  97. }
  98.  
  99. test_io_error (name)
  100.      char *name;
  101. {
  102.   extern int errno;
  103.   int old_errno = errno;
  104.   fprintf (stderr, "%s: ", argv[0]);
  105.   errno = old_errno;
  106.   perror (name);
  107.   test_exit (SHELL_BOOLEAN (FALSE));
  108. }
  109.  
  110. /*
  111.  * advance - increment our position in the argument list.  Check that
  112.  *    we're not past the end of the argument list.  This check is
  113.  *    supressed if the argument is FALSE.  made a macro for efficiency.
  114.  */
  115. #ifndef lint
  116. #define advance(f)    (++pos, f && (pos < argc ? 0 : beyond()))
  117. #endif
  118.  
  119. #if !defined(advance)
  120. static int
  121. advance (f)
  122.      int f;
  123. {
  124.   ++pos;
  125.   if (f && pos >= argc)
  126.     beyond ();
  127. }
  128.  
  129. #endif
  130.  
  131. #define unary_advance() (advance (1),++pos)
  132.  
  133. /*
  134.  * beyond - call when we're beyond the end of the argument list (an
  135.  *    error condition)
  136.  */
  137. static int
  138. beyond ()
  139. {
  140.   test_syntax_error ("argument expected\n", (char *)NULL);
  141. }
  142.  
  143. /*
  144.  * int_expt_err - when an integer argument was expected, but something else
  145.  *     was found.
  146.  */
  147. static void
  148. int_expt_err (pch)
  149.      char *pch;
  150. {
  151.   test_syntax_error ("integer expression expected %s\n", pch);
  152. }
  153.  
  154. /*
  155.  * isint - is the argument whose position in the argument vector is 'm' an
  156.  *     integer? Convert it for me too, returning it's value in 'pl'.
  157.  */
  158. static int
  159. isint (m, pl)
  160.      int m;
  161.      long *pl;
  162. {
  163.   extern long atol ();
  164.   register char *pch;
  165.  
  166.   pch = argv[m];
  167.  
  168.   /* Skip leading whitespace characters. */
  169.   while (*pch == '\t' || *pch == ' ')
  170.     pch++;
  171.  
  172.   /* accept negative numbers but not '-' alone */
  173.   if ('-' == *pch)
  174.     if ('\000' == *++pch)
  175.       return 0;
  176.  
  177.   while ('\000' != *pch)
  178.     {
  179.       switch (*pch)
  180.     {
  181.     case '0':
  182.     case '1':
  183.     case '2':
  184.     case '3':
  185.     case '4':
  186.     case '5':
  187.     case '6':
  188.     case '7':
  189.     case '8':
  190.     case '9':
  191.       break;
  192.     default:
  193.       return (FALSE);
  194.     }
  195.       ++pch;
  196.     }
  197.   *pl = atol (argv[m]);
  198.   return (TRUE);
  199. }
  200.  
  201. /*
  202.  * age_of - find the age of the given file.  Return YES or NO depending
  203.  *    on whether the file exists, and if it does, fill in the age with
  204.  *    the modify time.
  205.  */
  206. static int
  207. age_of (posit, age)
  208.      int posit;
  209.      long *age;
  210. {
  211.   struct stat stat_buf;
  212.  
  213.   if (stat (argv[posit], &stat_buf) < 0)
  214.     {
  215.       return (FALSE);
  216.     }
  217.   *age = stat_buf.st_mtime;
  218.   return (TRUE);
  219. }
  220.  
  221. /*
  222.  * term - parse a term and return 1 or 0 depending on whether the term
  223.  *    evaluates to true or false, respectively.
  224.  *
  225.  * term ::=
  226.  *    '-'('h'|'d'|'f'|'r'|'s'|'w'|'c'|'b'|'p'|'u'|'g'|'k') filename
  227.  *    '-'('L'|'x') filename
  228.  *     '-t' [ int ]
  229.  *    '-'('z'|'n') string
  230.  *    string
  231.  *    string ('!='|'=') string
  232.  *    <int> '-'(eq|ne|le|lt|ge|gt) <int>
  233.  *    file '-'(nt|ot|ef) file
  234.  *    '(' <expr> ')'
  235.  * int ::=
  236.  *    '-l' string
  237.  *    positive and negative integers
  238.  */
  239. static int
  240. term ()
  241. {
  242.   int expr ();
  243.   auto struct stat stat_buf, stat_spare;
  244.   auto long int l, r;
  245.   auto int l_is_l, r_is_l; /* are the left and right integer
  246.                 * expressions of the form '-l string'?
  247.                 */
  248.   auto int value, fd;
  249.  
  250.   if (pos >= argc)
  251.     beyond ();
  252.  
  253.   /* Deal with leading "not". */
  254.   if (pos < argc && '!' == argv[pos][0] && '\000' == argv[pos][1])
  255.     {
  256.       advance (1);
  257.  
  258.       /* This has to be rewritten to handle the TRUTH and FALSE stuff. */
  259.       return (!term ());
  260.     }
  261.   
  262.   if ('(' == argv[pos][0] && '\000' == argv[pos][1])
  263.     {
  264.       advance (1);
  265.       value = expr ();
  266.       if (')' != argv[pos][0] || '\000' != argv[pos][1])
  267.     test_syntax_error ("argument expected, found %s\n", argv[pos]);
  268.       advance (0);
  269.       return (TRUE == (value));
  270.     }
  271.   /* are there enough arguments left that this could be dyadic? */
  272.   if (pos + 3 <= argc)
  273.     {
  274.       register int op;
  275.       if ('-' == argv[pos][0] && 'l' == argv[pos][1] &&
  276.       '\000' == argv[pos][2])
  277.     {
  278.       l_is_l = 1;
  279.       op = pos + 2;
  280.       advance (0);
  281.     }
  282.       else
  283.     {
  284.       l_is_l = 0;
  285.       op = pos + 1;
  286.     }
  287.       if ('-' == argv[op + 1][0] && 'l' == argv[op + 1][1]
  288.       && '\000' == argv[op + 1][2])
  289.     {
  290.       r_is_l = 1;
  291.       advance (0);
  292.     }
  293.       else
  294.     r_is_l = 0;
  295.  
  296.       if ('-' == argv[op][0])
  297.     {
  298.       /* check for eq, nt, and stuff */
  299.       switch (argv[op][1])
  300.         {
  301.         default:
  302.           break;
  303.         case 'l':
  304.           if ('t' == argv[op][2] && '\000' == argv[op][3])
  305.         {
  306.           /* lt */
  307.           if (l_is_l)
  308.             l = strlen (argv[op - 1]);
  309.           else
  310.             {
  311.               if (!isint (op - 1, &l))
  312.             int_expt_err ("before -lt");
  313.             }
  314.  
  315.           if (r_is_l)
  316.             r = strlen (argv[op + 2]);
  317.           else
  318.             {
  319.               if (!isint (op + 1, &r))
  320.             int_expt_err ("after -lt");
  321.             }
  322.           pos += 3;
  323.           return (TRUE == (l < r));
  324.         }
  325.  
  326.           if ('e' == argv[op][2] && '\000' == argv[op][3])
  327.         {
  328.           /* le */
  329.           if (l_is_l)
  330.             l = strlen (argv[op - 1]);
  331.           else
  332.             {
  333.               if (!isint (op - 1, &l))
  334.             int_expt_err ("before -le");
  335.             }
  336.           if (r_is_l)
  337.             r = strlen (argv[op + 2]);
  338.           else
  339.             {
  340.               if (!isint (op + 1, &r))
  341.             int_expt_err ("after -le");
  342.             }
  343.           pos += 3;
  344.           return (TRUE == (l <= r));
  345.         }
  346.           break;
  347.  
  348.         case 'g':
  349.  
  350.           if ('t' == argv[op][2] && '\000' == argv[op][3])
  351.         {
  352.           /* gt integer greater than */
  353.           if (l_is_l)
  354.             l = strlen (argv[op - 1]);
  355.           else
  356.             {
  357.               if (!isint (op - 1, &l))
  358.             int_expt_err ("before -gt");
  359.             }
  360.           if (r_is_l)
  361.             r = strlen (argv[op + 2]);
  362.           else
  363.             {
  364.               if (!isint (op + 1, &r))
  365.             int_expt_err ("after -gt");
  366.             }
  367.           pos += 3;
  368.           return (TRUE == (l > r));
  369.         }
  370.  
  371.           if ('e' == argv[op][2] && '\000' == argv[op][3])
  372.         {
  373.           /* ge - integer greater than or equal to */
  374.           if (l_is_l)
  375.             l = strlen (argv[op - 1]);
  376.           else
  377.             {
  378.               if (!isint (op - 1, &l))
  379.             int_expt_err ("before -ge");
  380.             }
  381.           if (r_is_l)
  382.             r = strlen (argv[op + 2]);
  383.           else
  384.             {
  385.               if (!isint (op + 1, &r))
  386.             int_expt_err ("after -ge");
  387.             }
  388.           pos += 3;
  389.           return (TRUE == (l >= r));
  390.         }
  391.           break;
  392.  
  393.         case 'n':
  394.           if ('t' == argv[op][2] && '\000' == argv[op][3])
  395.         {
  396.           /* nt - newer than */
  397.           pos += 3;
  398.           if (l_is_l || r_is_l)
  399.             test_syntax_error ("-nt does not accept -l\n",
  400.                        (char *)NULL);
  401.           if (age_of (op - 1, &l) && age_of (op + 1, &r))
  402.             return (TRUE == (l > r));
  403.           else
  404.             return (FALSE);
  405.         }
  406.  
  407.           if ('e' == argv[op][2] && '\000' == argv[op][3])
  408.         {
  409.           /* ne - integer not equal */
  410.           if (l_is_l)
  411.             l = strlen (argv[op - 1]);
  412.           else
  413.             {
  414.               if (!isint (op - 1, &l))
  415.             int_expt_err ("before -ne");
  416.             }
  417.           if (r_is_l)
  418.             r = strlen (argv[op + 2]);
  419.           else
  420.             {
  421.               if (!isint (op + 1, &r))
  422.             int_expt_err ("after -ne");
  423.             }
  424.           pos += 3;
  425.           return (TRUE == (l != r));
  426.         }
  427.           break;
  428.  
  429.         case 'e':
  430.           if ('q' == argv[op][2] && '\000' == argv[op][3])
  431.         {
  432.           /* eq - integer equal */
  433.           if (l_is_l)
  434.             l = strlen (argv[op - 1]);
  435.           else
  436.             {
  437.               if (!isint (op - 1, &l))
  438.             int_expt_err ("before -eq");
  439.             }
  440.           if (r_is_l)
  441.             r = strlen (argv[op + 2]);
  442.           else
  443.             {
  444.               if (!isint (op + 1, &r))
  445.             int_expt_err ("after -eq");
  446.             }
  447.           pos += 3;
  448.           return (TRUE == (l == r));
  449.         }
  450.  
  451.           if ('f' == argv[op][2] && '\000' == argv[op][3])
  452.         {
  453.           /* ef - hard link? */
  454.           pos += 3;
  455.           if (l_is_l || r_is_l)
  456.             test_syntax_error ("-ef does not accept -l\n",
  457.                        (char *)NULL);
  458.           if (stat (argv[op - 1], &stat_buf) < 0)
  459.             return (FALSE);
  460.           if (stat (argv[op + 1], &stat_spare) < 0)
  461.             return (FALSE);
  462.           return (TRUE ==
  463.               (stat_buf.st_dev == stat_spare.st_dev &&
  464.                stat_buf.st_ino == stat_spare.st_ino));
  465.         }
  466.           break;
  467.  
  468.         case 'o':
  469.           if ('t' == argv[op][2] && '\000' == argv[op][3])
  470.         {
  471.           /* ot - older than */
  472.           pos += 3;
  473.           if (l_is_l || r_is_l)
  474.             test_syntax_error ("-nt does not accept -l\n",
  475.                        (char *)NULL);
  476.           if (age_of (op - 1, &l) && age_of (op + 1, &r))
  477.             return (TRUE == (l < r));
  478.           return (FALSE);
  479.         }
  480.           break;
  481.         }
  482.     }
  483.  
  484.       if ('=' == argv[op][0] && '\000' == argv[op][1])
  485.     {
  486.       value = (0 == strcmp (argv[pos], argv[pos + 2]));
  487.       pos += 3;
  488.       return (TRUE == value);
  489.     }
  490.       if ('!' == argv[op][0] && '=' == argv[op][1] && '\000' == argv[op][2])
  491.     {
  492.       value = 0 != strcmp (argv[pos], argv[pos + 2]);
  493.       pos += 3;
  494.       return (TRUE == value);
  495.     }
  496.     }
  497.  
  498.   /* Might be a switch type argument */
  499.   if ('-' == argv[pos][0] && '\000' == argv[pos][2] /* && pos < argc-1 */ )
  500.     {
  501.       switch (argv[pos][1])
  502.     {
  503.     default:
  504.       break;
  505.  
  506.       /* All of the following unary operators use unary_advance (), which
  507.          checks to make sure that there is an argument, and then advances
  508.          pos right past it.  This means that pos - 1 is the location of the
  509.          argument. */
  510.  
  511.     case 'r':        /* file is readable? */
  512.       unary_advance ();
  513.       value = -1 != access (argv[pos - 1], R_OK);
  514.       return (TRUE == value);
  515.  
  516.     case 'w':        /* File is writeable? */
  517.       unary_advance ();
  518.       value = -1 != access (argv[pos - 1], W_OK);
  519.       return (TRUE == value);
  520.  
  521.     case 'x':        /* File is executable? */
  522.       unary_advance ();
  523.       value = -1 != access (argv[pos - 1], X_OK);
  524.       return (TRUE == value);
  525.  
  526.     case 'O':        /* File is owned by you? */
  527.       unary_advance ();
  528.       if (stat (argv[pos - 1], &stat_buf) < 0)
  529.         return (FALSE);
  530.  
  531.       return (TRUE == (geteuid () == stat_buf.st_uid));
  532.  
  533.     case 'f':        /* File is a file? */
  534.       unary_advance ();
  535.       if (stat (argv[pos - 1], &stat_buf) < 0)
  536.         return (FALSE);
  537.  
  538.       /*
  539.        * Under SYSV, -f is true if the given file exists
  540.        * and is a regular file.  Other places, this checks
  541.        * to see if the given file is not a directory.
  542.        */
  543.       if (sys_v)
  544.         return (TRUE == ((S_IFREG == (stat_buf.st_mode & S_IFMT)) ||
  545.                  (0 == (stat_buf.st_mode & S_IFMT))));
  546.       else
  547.         return (TRUE == (S_IFDIR != (stat_buf.st_mode & S_IFMT)));
  548.  
  549.     case 'd':        /* File is a directory? */
  550.       unary_advance ();
  551.       if (stat (argv[pos - 1], &stat_buf) < 0)
  552.         return (FALSE);
  553.  
  554.       return (TRUE == (S_IFDIR == (stat_buf.st_mode & S_IFMT)));
  555.  
  556.     case 's':        /* File has something in it? */
  557.       unary_advance ();
  558.       if (stat (argv[pos - 1], &stat_buf) < 0)
  559.         return (FALSE);
  560.  
  561.       return (TRUE == (stat_buf.st_size > (off_t) 0));
  562.  
  563. #ifdef S_IFSOCK
  564.     case 'S':        /* File is a socket? */
  565.       unary_advance ();
  566.       if (stat (argv[pos - 1], &stat_buf) < 0)
  567.         return (FALSE);
  568.  
  569.       return (TRUE == (S_IFSOCK == (stat_buf.st_mode & S_IFMT)));
  570. #endif
  571.  
  572.     case 'c': /* File is character special? */
  573.       unary_advance ();
  574.       if (stat (argv[pos - 1], &stat_buf) < 0)
  575.         return (FALSE);
  576.  
  577.       return (TRUE == (S_IFCHR == (stat_buf.st_mode & S_IFMT)));
  578.  
  579.     case 'b':        /* File is block special? */
  580.       unary_advance ();
  581.       if (stat (argv[pos - 1], &stat_buf) < 0)
  582.         return (FALSE);
  583.  
  584.       return (TRUE == (S_IFBLK == (stat_buf.st_mode & S_IFMT)));
  585.  
  586.     case 'p':        /* File is a named pipe? */
  587.       unary_advance ();
  588. #ifndef S_IFIFO
  589.       return (FALSE);
  590. #else
  591.       if (stat (argv[pos - 1], &stat_buf) < 0)
  592.         return (FALSE);
  593.       return (TRUE == (S_IFIFO == (stat_buf.st_mode & S_IFMT)));
  594. #endif /* S_IFIFO */
  595.  
  596.     case 'L':        /* Same as -h  */
  597.       /*FALLTHROUGH*/
  598.  
  599.     case 'h':        /* File is a symbolic link? */
  600.       unary_advance ();
  601. #ifndef S_IFLNK
  602.       return (FALSE);
  603. #else
  604.       if (lstat (argv[pos - 1], &stat_buf) < 0)
  605.         return (FALSE);
  606.  
  607.       return (TRUE == (S_IFLNK == (stat_buf.st_mode & S_IFMT)));
  608. #endif /* S_IFLNK */
  609.  
  610.     case 'u':        /* File is setuid? */
  611.       unary_advance ();
  612.       if (stat (argv[pos - 1], &stat_buf) < 0)
  613.         return (FALSE);
  614.  
  615.       return (TRUE == (0 != (stat_buf.st_mode & S_ISUID)));
  616.  
  617.     case 'g':        /* File is setgid? */
  618.       unary_advance ();
  619.       if (stat (argv[pos - 1], &stat_buf) < 0)
  620.         return (FALSE);
  621.  
  622.       return (TRUE == (0 != (stat_buf.st_mode & S_ISGID)));
  623.  
  624.     case 'k':        /* File has sticky bit set? */
  625.       unary_advance ();
  626.       if (stat (argv[pos - 1], &stat_buf) < 0)
  627.         return (FALSE);
  628.       return (TRUE == (0 != (stat_buf.st_mode & S_ISVTX)));
  629.  
  630.     case 't':        /* File (fd) is a terminal?  (fd) defaults to stdout. */
  631.       advance (0);
  632.       if (pos < argc && isint (pos, &r))
  633.         {
  634.           advance (0);
  635.           return (TRUE == (isatty ((int) r)));
  636.         }
  637.       return (TRUE == (isatty (1)));
  638.  
  639.     case 'n':        /* True if arg has some length. */
  640.       unary_advance ();
  641.       return (TRUE == (0 != strlen (argv[pos - 1])));
  642.       break;
  643.  
  644.     case 'z':        /* True if arg has no length. */
  645.       unary_advance ();
  646.       return (TRUE == (0 == strlen (argv[pos - 1])));
  647.     }
  648.     }
  649.   value = 0 != strlen (argv[pos]);
  650.   advance (0);
  651.   return value;
  652. }
  653.  
  654. /*
  655.  * and:
  656.  *    and '-a' term
  657.  *    term
  658.  */
  659. static int
  660. and ()
  661. {
  662.   auto int value;
  663.  
  664.   value = term ();
  665.   while (pos < argc && '-' == argv[pos][0] && 'a' == argv[pos][1] && '\000' == argv[pos][2])
  666.     {
  667.       advance (0);
  668.       value = TRUTH_AND (value, term ());
  669.     }
  670.   return (TRUE == value);
  671. }
  672.  
  673. /*
  674.  * or:
  675.  *    or '-o' and
  676.  *    and
  677.  */
  678. static int
  679. or ()
  680. {
  681.   auto int value;
  682.  
  683.   value = and ();
  684.   while (pos < argc && '-' == argv[pos][0] && 'o' == argv[pos][1] && '\000' == argv[pos][2])
  685.     {
  686.       advance (0);
  687.       value = TRUTH_OR (value, and ());
  688.     }
  689.   return (TRUE == value);
  690. }
  691.  
  692. /*
  693.  * expr:
  694.  *    or
  695.  */
  696. int
  697. expr ()
  698. {
  699.   auto int value;
  700.  
  701.   if (pos >= argc)
  702.     beyond ();
  703.  
  704.   value = FALSE;
  705.  
  706.   return value ^ or ();        /* Same with this. */
  707. }
  708.  
  709. /*
  710.  * [:
  711.  *    '[' expr ']'
  712.  * test:
  713.  *    test expr
  714.  */
  715. int
  716. #ifdef STANDALONE
  717. main (margc, margv)
  718. #else
  719. test_command (margc, margv)
  720. #endif /* STANDALONE */
  721.      int margc;
  722.      char **margv;
  723. {
  724.   auto int value;
  725.   int expr ();
  726. #ifndef STANDALONE
  727.   int code = setjmp (test_exit_buf);
  728.  
  729.   if (code)
  730.     return (test_error_return);
  731. #endif /* STANDALONE */
  732.  
  733.   argv = margv;
  734.  
  735.   if (margv[0] && strcmp (margv[0], "[") == 0)
  736.     {
  737.       --margc;
  738.  
  739.       if (margc < 2)
  740.     test_exit (SHELL_BOOLEAN (FALSE));
  741.  
  742.       if (margv[margc] && strcmp (margv[margc], "]") != 0)
  743.     test_syntax_error ("missing `]'\n", (char *)NULL);
  744.     }
  745.  
  746.   argc = margc;
  747.   pos = 1;
  748.  
  749.   if (pos >= argc)
  750.     test_exit (SHELL_BOOLEAN (FALSE));
  751.  
  752.   value = expr ();
  753.   if (pos != argc)
  754.     test_syntax_error ("too many arguments\n", (char *)NULL);
  755.  
  756.   test_exit (SHELL_BOOLEAN (value));
  757. }
  758.